<?php
/**
* Copyright (c) 2002-2007 BioWare Corp.
* http://www.bigdaddymonitor.org
*
* This file is part of the BigDaddy Monitoring
* program. It is free software distributed under
* the terms of the BSD License. It is ditributed
* in the hopes that it will be useful, but
* WITHOUT ANY WARRANTY; without event the implied
* warranty of MERCHANTABILITY or FITNESS FOR A
* PARTICULAR PURPOSE.
*
* The BSD License is available from:
* http://www.opensource.org/licenses/bsd-license.php
**/
/*--------------------------------------------------------------------------------------
 Class::Role
 Created by Duleepa Wijayawardhana
 August 18, 2005

 Description: Contains the core methods for the Role System.
 Documentation for the Role System is available at:
 http://staff.bioware.com/wiki/index.html?page=RoleSystemMain&wiki=websystems&action=view
 
 --------------------------------------------------------------------------------------*/
class Role
{
    ///Stores the current logged in user roles
    protected $aLoggedInUserRole = array();
    //Stores the current logged in user role strings (backwards compat with the
    //old access Groups
    protected $aLoggedInUserRoleString = array();
    //Stores the global actions for the logged in user related to the logged in users' role
    protected $aLoggedInUserGlobalActions = array();
    //Stores the current logged in user's roleTypes with names and roleIDs associated with
    //it. Structure:
    //array[roleTypeID][n][0]=roleID
    //array[roleTypeID][n][1]=name
    public $aLoggedInUserRoleType = array();
    
    //Variable to hold the Audit Class
    protected $Audit;
    //protected $Date;
    
    //Contains the employee Class
    private $Employee;

    public $aErrors;
    public $aMessages;
    
    
    /*---------------------------------------------------------------------------------
      void __construct ()
      Created by Duleepa Wijayawardhana
      August 18, 2005
      
      Description: constructor for Role class.
      ---------------------------------------------------------------------------------*/
    function __construct()
    {
        $this->GetMyRoles();
        $this->GetMyGlobalActions();
        
        $this->Audit=$GLOBALS["Audit"];
        //$this->Employee = new Employee;
		//$this->Date = new Date();
    }
    
    /*---------------------------------------------------------------------------------
      array GetMyRoles()
      Created by Duleepa Wijayawardhana
      August 18, 2005
      
      Description: Gets all the Roles in the database for the logged in username.
	roles can now have dates attached!  this returns any roles that have NO date
	attached (i.e. 'admin' or most access roles), or they can have start/end dates
	if it is a times membership in the role.  This function returns the roles that the 
	loggedin user is in RIGHT NOW.
      ---------------------------------------------------------------------------------*/
    protected function GetMyRoles($sDate = null)
    {
		if(!$sDate || strlen($sDate) <= 0)
		{
			$sDate = date("Y-m-d H:i:s");
		}
		$sDateSQL = " AND (rU.startDate <= '" . db_escape_string($sDate) . "' 
			AND (rU.endDate > '" . db_escape_string($sDate) . "' OR rU.endDate = 0)) ";
	
		$sql="SELECT rU.roleID, r.roleStringID, r.roleTypeID, rD.name
			FROM roleUser rU
			LEFT JOIN role r ON r.ID=rU.roleID
			LEFT JOIN roleDefinition rD ON r.roleDefinitionID=rD.ID
		WHERE rU.username='" . LOGGEDIN_USERNAME . "'
		$sDateSQL
		";
		$aResult=db_fetch_array(db_query($sql));
		
		if (is_array($aResult))
		{
			for ($i=0; $i<count($aResult); $i++)
			{
				$this->aLoggedInUserRole[]=$aResult[$i]["roleID"];
				$this->aLoggedInUserRoleType[$aResult[$i]["roleTypeID"]][]=array($aResult[$i]["roleID"], $aResult[$i]["name"]);
				if ($aResult[$i]["roleStringID"]!="")
				{
					$this->aLoggedInUserRoleString[]=$aResult[$i]["roleStringID"];
				}
				
			}
		}
    }

    /*---------------------------------------------------------------------------------
      array GetMyGlobalActions()
      Created by Duleepa Wijayawardhana
      August 24, 2005
      
      Description: Retrieves the string actions which are set in the roleGlobalActions
      This stores it in a protected variable and is checked by the IsUserAbleToDoGlobalAction
      ---------------------------------------------------------------------------------*/
    protected function GetMyGlobalActions()
    {

        $sRoleString="";
        if (is_array($this->aLoggedInUserRole))
        {
            $sRoleString=implode(",", $this->aLoggedInUserRole);
        }
        
        $sql="SELECT rA.type
            FROM roleGlobalAction rGA
            LEFT JOIN roleAction rA ON rA.ID=rGA.actionID
            WHERE rGA.roleID IN (".$sRoleString.")";
        $aResult=db_fetch_array(db_query($sql));

        if (is_array($aResult))
        {
            for ($i=0; $i<count($aResult); $i++)
            {
                $this->aLoggedInUserGlobalActions[]=$aResult[$i]["type"];
            }
        }
    }

    /*---------------------------------------------------------------------------------
      array GetMyRolesArray()
      Created by Duleepa Wijayawardhana
      August 18, 2005
      
      Description: Returns the private aLoggedInUserRole... aLoggedInUserRole is private
      to prevent modification, but it can be read from this function. All checks must be
      against the private variable within this class.
      ---------------------------------------------------------------------------------*/
    public function GetMyRolesArray()
    {
        return $this->aLoggedInUserRole;
    }
    
    /*---------------------------------------------------------------------------------
      array GetMyRolesStringArray()
      Created by Duleepa Wijayawardhana
      August 18, 2005
      
      Description: Returns the private aLoggedInUserRoleString... aLoggedInUserRoleString is private
      to prevent modification, but it can be read from this function. All checks must be
      against the private variable within this class.
      ---------------------------------------------------------------------------------*/
    public function GetMyRolesStringArray()
    {
        return $this->aLoggedInUserRoleString;
    }
    
    /*---------------------------------------------------------------------------------
      array GetMyGlobalActionsArray()
      Created by Duleepa Wijayawardhana
      August 24, 2005
      
      Description: Returns the private aLoggedInUserGlobalActions... aLoggedInUserGlobalActions is private
      to prevent modification, but it can be read from this function. All checks must be
      against the private variable within this class.
      ---------------------------------------------------------------------------------*/
    public function GetMyGlobalActionsArray()
    {
        return $this->aLoggedInUserGlobalActions;
    }
    
    /*---------------------------------------------------------------------------------
      array GetMyActionableRoleTypes (string sRelationshipType, string ActionType)
      Created by Duleepa Wijayawardhana
      August 19, 2005
      
      Description: Get's role types which have a relationship to the roles logged in
      user is in.
      
      Returns:
      
      -1 => No Relationship Type
      -2 => No acttion type
      ---------------------------------------------------------------------------------*/
    public function GetMyActionableRoleTypes($sRelationshipType, $sActionType)
    {
        
        if ($sRelationshipType=="")
        {
	    $this->aErrors[] = "no relationship type specified";
            return -1;
        }
        
        if ($sActionType=="")
        {
	    $this->aErrors[] = "no action type specified";
            return -2;
        }
      
        $sRoleString="";
        if (is_array($this->aLoggedInUserRole))
        {
            $sRoleString=implode(",",$this->aLoggedInUserRole);
        }
        
        $sql="SELECT rTR.roleTypeID
            FROM roleTypeRelationship rTR
            LEFT JOIN roleAction rA ON rA.ID=rTR.actionID
            WHERE rA.type='".$sActionType."'
                AND rTR.relationshipType='".$sRelationshipType."'
                AND rTR.primaryRoleID IN (".$sRoleString.")";
        $aResult=db_fetch_array(db_query($sql));
        
        if (is_array($aResult))
        {
            for ($i=0; $i<count($aResult); $i++)
            {
                $aReturn[]=$aResult[$i]["roleTypeID"];
            }
        }
        return $aReturn;
        
    }
    /*---------------------------------------------------------------------------------
      array GetActionsByRoleAndObjectID (string sRelationshipType, array aRole, int objectID[, string sType])
      Created by Duleepa Wijayawardhana
      September 1, 2005
      
      Description: Get the actions I am allowed to perform on the passed in
      array of roles based on the passed in relationship type and objectID. You can
      also narrow what is returned by specifying an action Type. Returns the following
      data structure:
      
      [<RoleID>]["action"]=<actionType>
      [<RoleID>]["type"]=<actionType>
      
      ---------------------------------------------------------------------------------*/
    public function GetActionsByRoleAndObjectID($sRelationshipType, $aRole, $nObjectID, $sType=NULL)
    {
        if ($sRelationshipType=="")
        {
	    $this->aErrors[] = "no relationship type specified";
            return;
        }
        
        if (!is_array($aRole))
        {
	    $this->aErrors[] = "no roles array specified";
            return;
        }
        
        if ($nObjectID<1 || !is_numeric($nObjectID))
        {
	    $this->aErrors[] = "no object ID specified";
            return;
        }
        
        
        if ($sType!="")
        {
            $sSQLSubStr=" AND rA.type='".$sType."' ";
        }

        $sRoleString="";
        if (is_array($this->aLoggedInUserRole))
        {
            $sRoleString=implode(",", $this->aLoggedInUserRole);
        }
        $sSecondaryRoleString=implode(",", $aRole);
        
        $sql="SELECT rR.secondaryRoleID, rA.type
            FROM roleRelationship rR
            LEFT JOIN roleAction rA ON rA.ID=rR.actionID
            WHERE rR.relationshipType='".$sRelationshipType."'
            ".$sSQLSubStr."
            AND rR.primaryRoleID IN (".$sRoleString.")
            AND rR.objectID=".$nObjectID."
            AND rR.secondaryRoleID IN (".$sSecondaryRoleString.")";
        $aResult=db_fetch_array(db_query($sql));
        
        if (is_array($aResult))
        {
            for ($i=0; $i<count($aResult); $i++)
            {
                $aReturn[$aResult[$i]["secondaryRoleID"]]["action"]=$aResult[$i]["type"];
                $aReturn[$aResult[$i]["secondaryRoleID"]]["type"]=$aResult[$i]["type"];
            }
        }
        return $aReturn;
    }

    /*---------------------------------------------------------------------------------
      array GetMyActionsOnRole (string sRelationshipType, array aRole[, string sType])
      Created by Duleepa Wijayawardhana
      August 19, 2005
      
      Description:
      Role Relationship type is the category of roles, e.g. rolesystem, extraview,
      organization etc.
      
      Get the actions I am allowed to perform on the passed in
      array of roles based on the passed in relationship type. You can
      also narrow what is returned by specifying an action Type. Returns the following
      data structure:
      
      [<RoleID>]["action"]=<actionType>
      [<RoleID>]["type"]=<actionType>
      
      ---------------------------------------------------------------------------------*/
    public function GetMyActionsOnRole($sRelationshipType, $aRole, $sType=NULL)
    {
        if ($sRelationshipType=="")
        {
	    $this->aErrors[] = "no relationship type specified";
            return;
        }
        
        if (!is_array($aRole) || count($aRole) <= 0)
        {
	    $this->aErrors[] = "no roles array specified";
            return;
        }
        
        if ($sType!="")
        {
            $sSQLSubStr=" AND rA.type='".$sType."' ";
        }

        $sRoleString="";
        if (is_array($this->aLoggedInUserRole))
        {
            $sRoleString=implode(",", $this->aLoggedInUserRole);
        }
        $sSecondaryRoleString=implode(",", $aRole);
        
        $sql="SELECT rR.secondaryRoleID, rA.type
            FROM roleRelationship rR
            LEFT JOIN roleAction rA ON rA.ID=rR.actionID
            WHERE rR.relationshipType='".$sRelationshipType."'
            ".$sSQLSubStr."
            AND rR.primaryRoleID IN (".$sRoleString.")
            AND rR.secondaryRoleID IN (".$sSecondaryRoleString.")";
        $aResult=db_fetch_array(db_query($sql));
        
        if (is_array($aResult))
        {
            for ($i=0; $i<count($aResult); $i++)
            {
                $j=count($aReturn[$aResult[$i]["secondaryRoleID"]]);
                $aReturn[$aResult[$i]["secondaryRoleID"]][$j]["action"]=$aResult[$i]["type"];
                $aReturn[$aResult[$i]["secondaryRoleID"]][$j]["type"]=$aResult[$i]["type"];
            }
        }
        return $aReturn;

    }

    /*---------------------------------------------------------------------------------
      array GetMyActionsOnRoleType (string sRelationshipType, array aRole[, string sType])
      Created by Duleepa Wijayawardhana
      August 19, 2005
      
      Description: Get the actions I am allowed to perform on the passed in
      array of roleTypes based on the passed in relationship type. You can
      also narrow what is returned by specifying an action Type. Returns the following
      data structure:
      
      [<RoleTypeID>]["action"]=<actionType>
      [<RoleTypeID>]["type"]=<actionType>

      ---------------------------------------------------------------------------------*/
    public function GetMyActionsOnRoleType($sRelationshipType, $aRoleType, $sType=NULL)
    {
        if ($sRelationshipType=="")
        {
	    $this->aErrors[] = "no relationship type specified";
            return;
        }
        
        if (!is_array($aRoleType) || count($aRoleType) <= 0)
        {
	    $this->aErrors[] = "no role types specified";
            return;
        }
        
        if ($sType!="")
        {
            $sSQLSubStr=" AND rA.type='".$sType."' ";
        }

        $sRoleString="";
        if (is_array($this->aLoggedInUserRole))
        {
            $sRoleString=implode(",",$this->aLoggedInUserRole);
        }
        $sRoleTypeString=implode(",",$aRoleType);
        
        $sql="SELECT rTR.roleTypeID, rA.type
            FROM roleTypeRelationship rTR
            LEFT JOIN roleAction rA ON rA.ID=rTR.actionID
            WHERE rTR.relationshipType='".$sRelationshipType."'
            ".$sSQLSubStr."
            AND rTR.primaryRoleID IN (".$sRoleString.")
            AND rTR.roleTypeID IN (".$sRoleTypeString.")";
        $aResult = db_fetch_array(db_query($sql));
        
        if (is_array($aResult))
        {
	    foreach($aResult as $aRow)
	    {
		$nRoleTypeID = $aRow["roleTypeID"];
		$sType = $aRow["type"];
		
		$aReturnRow = array("action" => $sType, "type" => $sType);
	    	$aReturn[ $nRoleTypeID ][] = $aReturnRow;
            }
        }
        return $aReturn;

    }

    /*---------------------------------------------------------------------------------
      array GetRoleTypeByTypeID (array aTypeID)
      Created by Duleepa Wijayawardhana
      August 21, 2005
      
      Description: Get's the roleType information by passed in array of RoleTypes.
      Expects array to be ID1, ID2, ID3
      ---------------------------------------------------------------------------------*/
    public function GetRoleTypeByTypeID ($aTypeID)
    {
        if (!is_array($aTypeID))
        {
	    $this->aErrors[] = "no role type ID specified";
            return;
        }
        
        $sTypeIDString=implode(",",$aTypeID);
        
        $sql="SELECT ID, name, description, maxAllowed
            FROM roleType
            WHERE ID IN (".$sTypeIDString.")
            ORDER BY name ASC";
        $aResult=db_fetch_array(db_query($sql));
        
        return $aResult;
    }

    /*---------------------------------------------------------------------------------
      array GetRoleTypeByTypeStringID (array aTypeStringID)
      Created by Jesse van Herk <jesse@>
      Jan 9, 2006
      
      Description: Get's the roleType information by passed in array of roleType String IDs.
      Expects array to be ID1, ID2, ID3
      ---------------------------------------------------------------------------------*/
    public function GetRoleTypeByTypeStringID ($aTypeID)
    {
        if (!is_array($aTypeID))
        {
	    $this->aErrors[] = "no role types specified";
            return;
        }
        
        $sTypeIDString=implode(",",$aTypeID);
        
        $sql="SELECT ID, name, description, maxAllowed
            FROM roleType
            WHERE stringID IN (".$sTypeIDString.")
            ORDER BY name ASC";
        $aResult=db_fetch_array(db_query($sql));
        
        return $aResult;
    }

    /*---------------------------------------------------------------------------------
      int GetRoleTypeIDByRoleID (int mRoleID)
      Created by Duleepa Wijayawardhana
      August 25, 2005
      
      Description: Returns the RoleTypeID for a particular RoleID

      Arguments:
	$mRoleID : either an integer role ID or an array of integer role IDs

      Returns: if $mRoleID is an integer, returns a single integer representing the role type
		    for that role ID.
	       if $mRoleID is an array of ints, returns an array of roleTypeIDs, in the same order
		    as the input.
      ---------------------------------------------------------------------------------*/
    public function GetRoleTypeIDByRoleID ($mRoleID)
    {
	$bReturnArray = false; // we assume we're looking up a single int, by default
	if(is_array($mRoleID) && count($mRoleID) > 0)
	{
	    $sRoleIDs = join(",", $mRoleID);
	    $bReturnArray = true;
	}
	elseif((int)$mRoleID > 0) // valid ID
	{
	    $sRoleIDs = (int)$mRoleID;
	}
	else
	{
	    $this->aErrors[] = "no role ID specified";
	    return;
	}
        
	// get the roleID so we can be sure of getting things in the right order
        $sql="SELECT ID,roleTypeID
            FROM role
            WHERE ID IN (" . $sRoleIDs . ")";
        
        $aResult = db_fetch_array(db_query($sql));
        
	if(is_array($aResult))
	{
	    foreach($aResult as $aData)
	    {
		$sRoleID = $aData["ID"];
		$sRoleTypeID = $aData["roleTypeID"];
		
		if($bReturnArray)
		{
		    $aIDs[$sRoleID] = $sRoleTypeID; // this isn't the final array, just yet.
		}
		else
		{
		    $mReturn = $sRoleTypeID; // will return just a single int.
		}
	    }

	    // now sort the results to match the input.
	    if(is_array($mRoleID))
	    {
		foreach ($mRoleID as $nRoleID)
		{
		    $nRoleTypeID = $aIDs[$nRoleID];
		    $aSorted[] = $nRoleTypeID;
		}
		$mReturn = $aSorted; // copy into the variable we actually return.
	    }
	}
        return $mReturn;
    }
    
    /*---------------------------------------------------------------------------------
      array GetRolesByTypeID (int nTypeID)
      Created by Duleepa Wijayawardhana
      August 21, 2005
      
      Description: Get's a list of roles by typeID
      ---------------------------------------------------------------------------------*/
    public function GetRolesByTypeID($nTypeID, $sOptions=NULL)
    {
        if (!is_numeric($nTypeID) || $nTypeID<1)
        {
	    $this->aErrors[] = "no role type ID specified";
            return;
        }
        
        if ($sOptions!=NULL)
        {
            $aOptions=explode(",",$sOptions);
            
            foreach ($aOptions as $sKey)
            {
                if ($sKey=="ORDER_BY_NOTES_FIELD")
                {
                    $sOrderBy="ORDER BY r.notes ASC, rD.name ASC";
                }
            }
        }
        
        if ($sOrderBy=="")
        {
            $sOrderBy="ORDER BY rD.name ASC";
        }
        
        $sql="SELECT r.ID, rD.name, rD.code
            FROM role r
            LEFT JOIN roleDefinition rD ON rD.ID=r.roleDefinitionID
            WHERE r.roleTypeID='".$nTypeID."'
            ".$sOrderBy;
        $aResult=db_fetch_array(db_query($sql));
        
        return $aResult;
    }

    /*---------------------------------------------------------------------------------
      array GetRolesByTypeStringID (string sTypeID)
      Created by Duleepa Wijayawardhana
      September 21, 2005
      
      Description: Get's a list of roles by string typeID
      
      Returns
      
      -1 => No StringID
      ---------------------------------------------------------------------------------*/
    public function GetRolesByTypeStringID($sTypeID, $sOptions=NULL)
    {
        if ($sTypeID=="" || $sTypeID === null)
        {
	    $this->aErrors[] = "no role type specified";
            return -1;
        }
        
        if ($sOptions!=NULL)
        {
            $aOptions=explode(",",$sOptions);
            
            foreach ($aOptions as $sKey)
            {
                if ($sKey=="ORDER_BY_NOTES_FIELD")
                {
                    $sOrderBy="ORDER BY r.notes ASC, rD.name ASC";
                }
            }
        }
        
        if ($sOrderBy=="")
        {
            $sOrderBy="ORDER BY rD.name ASC";
        }
        
        $sql="SELECT r.ID, rD.name, rD.code, r.roleStringID
            FROM role r
            LEFT JOIN roleDefinition rD ON rD.ID=r.roleDefinitionID
            LEFT JOIN roleType rT ON rT.ID=r.roleTypeID
            WHERE rT.stringID='".$sTypeID."'
            ".$sOrderBy;
        $aResult=db_fetch_array(db_query($sql));
        
        return $aResult;
    }

    /*---------------------------------------------------------------------------------
      array GetRolesByTypeIDAndUsername (mixed mTypeID[, string sUsername])
      Created by Duleepa Wijayawardhana
      September 15, 2005
      
      Description: Get's a list of roles by mixed typeID and optional sUsername
      
      Returns:
      
      -1 Could not verify the type of mTypeID
      -2 Supplied String could not match roleTYpeID
      -3 No results
      ---------------------------------------------------------------------------------*/
    public function GetRolesByTypeIDAndUsername($mTypeID, $sUsername = null, $sDate = null)
    {
        if ($sUsername==NULL)
        {
            $sUsername=LOGGEDIN_USERNAME;
        }

        if (!is_numeric($mTypeID))
        {
            $sql="SELECT ID
                FROM roleType
                WHERE stringID='".$mTypeID."'";
            $aResult=db_fetch_result(db_query($sql));
            
            if ($aResult["ID"]>0)
            {
                $nTypeID=$aResult["ID"];
            }
            else
            {
		$this->aErrors[] = "no roles found";
                return -2;
            }
        }
        elseif (is_numeric($mTypeID) && $mTypeID>0)
        {
            $nTypeID=$mTypeID;
        }
        else
        {
	    $this->aErrors[] = "invalid role type specified";
            return -1;
        }

	if(!$sDate || strlen($sDate) <= 0)
	{
	    $sDate = date("Y-m-d H:i:s");
	}
	$sDateSQL = " AND (rU.startDate <= '" . db_escape_string($sDate) . "' 
	    AND (rU.endDate > '" . db_escape_string($sDate) . "' OR rU.endDate = 0)) ";
        
        $sql="SELECT rU.roleID, rD.name
            FROM roleUser rU
            LEFT JOIN role r ON r.ID=rU.roleID
            LEFT JOIN roleDefinition rD ON rD.ID=r.roleDefinitionID
            WHERE r.roleTypeID='".$nTypeID."' AND
	    rU.username='".$sUsername."'
	    $sDateSQL
            ORDER BY rD.name ASC";
        $aResult=db_fetch_array(db_query($sql));
        
        if (is_array($aResult))
        {
            return $aResult;
        }
        else
        {
	    $this->aErrors[] = "no roles found";
            return -3;
        }
    }

    /*---------------------------------------------------------------------------------
      array GetRolesByTypeIDAndUsernameArray (mixed mTypeID, array aUsername)
      @author Duleepa Wijayawardhana <dups@bioware.com>
      @version 25/04/2006 14:14:14
      
      Description: Get's a list of roles by mixed typeID and array of usernames
      
      Returns:
      
      -1 Could not verify the type of mTypeID
      -2 Supplied String could not match roleTYpeID
      -3 No results
      -4 usernames not an array
      ---------------------------------------------------------------------------------*/
    public function GetRolesByTypeIDAndUsernameArray($mTypeID, $aUsername)
    {
        if (!is_numeric($mTypeID))
        {
            $sql="SELECT ID
                FROM roleType
                WHERE stringID='".$mTypeID."'";
            $aResult=db_fetch_result(db_query($sql));
            
            if ($aResult["ID"]>0)
            {
                $nTypeID=$aResult["ID"];
            }
            else
            {
		$this->aErrors[] = "no roles found";
                return -2;
            }
        }
        elseif (is_numeric($mTypeID) && $mTypeID>0)
        {
            $nTypeID=$mTypeID;
        }
        else
        {
	    $this->aErrors[] = "invalid type ID specified";
            return -1;
        }
        
	if(is_array($aUsername) && count($aUsername) > 0)
	{
	    $sUsernameSQL = "'" . implode("','", $aUsername) . "'";
	}
	else
	{
	    $this->aErrors[] = "no usernames specified";
	    return -4;
	}

	if(!$sDate || strlen($sDate) <= 0)
	{
	    $sDate = date("Y-m-d H:i:s");
	}
	$sDateSQL = " AND (rU.startDate <= '" . db_escape_string($sDate) . "' 
	    AND (rU.endDate > '" . db_escape_string($sDate) . "' OR rU.endDate = 0)) ";

        $sql="SELECT rU.username, rU.roleID, rD.name
            FROM roleUser rU
            LEFT JOIN role r ON r.ID=rU.roleID
            LEFT JOIN roleDefinition rD ON rD.ID=r.roleDefinitionID
            WHERE r.roleTypeID='".$nTypeID."' AND
	    rU.username IN ($sUsernameSQL)
	    $sDateSQL";
        $aResult=db_fetch_array(db_query($sql));
        
        if (is_array($aResult))
        {
            foreach ($aResult as $nIndex => $aInfo)
            {
                $i = count($aReturn[$aInfo["username"]]);
                $aReturn[$aInfo["username"]][$i]["roleID"] = $aInfo["roleID"];
                $aReturn[$aInfo["username"]][$i]["name"] = $aInfo["name"];
            }
            return $aReturn;
        }
        else
        {
	    $this->aErrors[] = "no roles found";
            return -3;
        }
    }

    /*---------------------------------------------------------------------------------
      int SetRoleByUsername (int nRoleID, string sUsername, $aLookupActionType, string sRelationshipType, string sStartDate, string sEndDate)
      Created by Duleepa Wijayawardhana
      August 25, 2005
      
      Description: Set's the specified username into the given role.
      
      Arguments:
	$aLookUpActionType should contain the following
	    "role" => "actionType"
	    "roleType" => "actionType"
      
	Where basically this function will check for the correct actionType versus these
	two tabular lookups. If any of this users roles contain the searched for action
	Types then it will allow the set.
      
	$sRelationshipType: should generally be "rolesystem"; used to check if we are allowed
		to set this user into this role.  
	$sStartDate: IF this is a temporary role membership, specifies a start date in MySQL format. OPTIONAL.
	$sEndDate: IF this is a temporary role membership, specifies an end date in MySQL format. OPTIONAL.
      
      Returns:
      
	  0 = success
	  -1 = Not allowed
	  -2 = Max Number Reached for RoleType
	  -3 = No Roles provided
	  -4 = No Lookup action to resolve permissions
	  -5 = No Relationship Type passed in
	  -6 = There was no active employee associated with this sUsername
      
      ---------------------------------------------------------------------------------*/
    public function SetRoleByUsername($nRoleID, $sUsername, $aLookupActionType, $sRelationshipType, $sStartDate = null, $sEndDate = null)
    {
        if (!is_numeric($nRoleID) || $nRoleID<1)
        {
            //No Role Provided
	    $this->aErrors[] = "no role specified";
            return -3;
        }
        
        if (!array($aLookupActionType))
        {
            //No lookup actiontypes provided
	    $this->aErrors[] = "no lookup action type specified";
            return -4;
        }
        
        if ($sRelationshipType=="")
        {
            //No Relationship Type specified
	    $this->aErrors[] = "no relationship type specified";
            return -5;
        }

	$sUsername = trim($sUsername); // remove wacky spaces/other invisible characters
        
        //Check the employee DB and make sure there is actually an employee of this type
		/*
        if (!$this->Employee->IsActiveEmployee($sUsername, "all") && !$this->Employee->IsSpecialAccount($sUsername))
        {
	    $this->aErrors[] = "There is no active employee associated with this username";
            return -6;
        }
		*/

        $nRoleTypeID = $this->GetRoleTypeIDByRoleID($nRoleID);
        $bAllowSet = $this->IsActionAllowedOnRole($nRoleID, $nRoleTypeID, $aLookupActionType, $sRelationshipType);

        //If we don't have permission return a 1 for failure code
        if (!$bAllowSet)
        {
    	    $this->aErrors[] = "you do not have permission to set this role for $sUsername";
            return -1;
        }
        
        //Check to see if the maxNumber has been set for this role Type
	$bNotConnectedToRoleType = false;
        if ($nRoleTypeID>0)
        {
            $aRoleTypeInfo=$this->GetRoleTypeByTypeID(array($nRoleTypeID));
        }
        else
        {
            $bNotConnectedToRoleType = true;
        }
        
	// see how many of these roles they are already in.
	$nUserRoleCount = $this->countUserRolesByType($sUsername, $nRoleTypeID, $sStartDate, $sEndDate);
	// set the role, if the user is not yet in their max number of roles for this 
	// role type, OR there is no max number of roles for this role type, OR this 
	// role has no role type.
        if ($nUserRoleCount < $aRoleTypeInfo["maxNumber"] || $aRoleTypeInfo["maxNumber"] == 0 || $bNotConnectedToRoleType)
        {
	    // no longer delete rows, because we have added a unique key!
	    $sql = "INSERT INTO roleUser SET username='" 
		. db_escape_string($sUsername) . "',roleID="
		. (int)$nRoleID;
	    if(strlen($sStartDate) > 0)
	    {
		$sql .= ",startDate='" . db_escape_string($sStartDate) . "'";
	    }
	    if(strlen($sEndDate) > 0)
	    {
		$sql .= ",endDate='" . db_escape_string($sEndDate) . "'";
	    }
            db_query($sql);
            
            $aOptions=array(
            "usernameAffected" => $sUsername,
            "primaryNumericID" => $nRoleID,
            "type" => "roleUser",
            "action" => "change"
            );
            $this->Audit->SetAudit($aOptions, "rolesystem");
        }
        else
        {
            //Already reached max number, remove before adding anymore.
	    $this->aErrors[] = "user already in max number of roles for this role type.";
            return -2;
        }

        //Success
        return 0;
    }

    /*---------------------------------------------------------------------------------
      int SetMyRole (int nRoleID, $aLookupActionType, string sRelationshipType)
      Created by Duleepa Wijayawardhana
      August 21, 2005
      
      Description: Set's role for the current logged in user
      $aLookUpActionType should contain the following
      "role" => "actionType"
      "roleType" => "actionType"
      
      Where basically this function will check for the correct actionType versus these
      two tabular lookups. If any of this users roles contain the searched for action
      Types then it will allow the set.
      
      You must also pass in the sRelationshipType, for instance "rolesystem" for RoleSystem
      functions
      
      Returns:
      
      0 = success
      -1 = Not allowed
      -2 = Max Number Reached for RoleType
      -3 = No Roles provided
      -4 = No Lookup action to resolve permissions
      -5 = No Relationship Type passed in
      
      ---------------------------------------------------------------------------------*/
    public function SetMyRole($nRoleID, $aLookupActionType, $sRelationshipType)
    {
	// DIRTY DILLIPS!  Why copy and paste when you can just pass in the username??
	return $this->SetRoleByUsername($nRoleID, LOGGEDIN_USERNAME, $aLookupActionType, $sRelationshipType);
        
    }

    /*---------------------------------------------------------------------------------
      int RemoveRoleByUsername (int nRoleID, $sUsername, $aLookupActionType, string sRelationshipType)
      Created by Duleepa Wijayawardhana
      August 25, 2005
      
      Description: Removes role for specified username
      $aLookUpActionType should contain the following
      "role" => "actionType"
      "roleType" => "actionType"
      
      Where basically this function will check for the correct actionType versus these
      two tabular lookups. If any of this users roles contain the searched for action
      Types then it will allow the remove.
      
      You must also pass in the sRelationshipType, for instance "rolesystem" for RoleSystem
      functions
      
      Returns:
      
      0 = success
      -1 = Not allowed
      -2 = No Roles provided
      -3 = No Lookup action to resolve permissions
      -4 = No Relationship Type passed in
      
      ---------------------------------------------------------------------------------*/
    public function RemoveRoleByUsername($nRoleID, $sUsername, $aLookupActionType, $sRelationshipType)
    {
        if (!is_numeric($nRoleID) || $nRoleID<1)
        {
            //No Role Provided
	    $this->aErrors[] = "no role specified";
            return -2;
        }
        
        if (!array($aLookupActionType))
        {
            //No lookup actiontypes provided
	    $this->aErrors[] = "no lookup action type specified";
            return -3;
        }
        
        if ($sRelationshipType=="")
        {
            //No Relationship Type specified
	    $this->aErrors[] = "no relationship type specified";
            return -4;
        }


        $nRoleTypeID=$this->GetRoleTypeIDByRoleID($nRoleID);
        $bAllowRemove=$this->IsActionAllowedOnRole($nRoleID, $nRoleTypeID, $aLookupActionType, $sRelationshipType);
        
               
        //If we don't have permission return a 1 for failure code
        if ($bAllowRemove==0)
        {
    	    $this->aErrors[] = "you do not have permission to remove users from role";
            return -1;
        }
        
	// FIXME! should check dates!  
        $sql="DELETE FROM roleUser WHERE username='".$sUsername."' AND roleID='".$nRoleID."'";
        db_query($sql);
        
        $aOptions=array(
            "usernameAffected" => $sUsername,
            "primaryNumericID" => $nRoleID,
            "type" => "roleUser",
            "action" => "delete"
            );
        $this->Audit->SetAudit($aOptions, "rolesystem");
        
        //Success
        return 0;
    }

    /*---------------------------------------------------------------------------------
      int RemoveMyRole (int nRoleID, $aLookupActionType, string sRelationshipType)
      Created by Duleepa Wijayawardhana
      August 21, 2005
      
      Description: Removes role for the current logged in user
      $aLookUpActionType should contain the following
      "role" => "actionType"
      "roleType" => "actionType"
      
      Where basically this function will check for the correct actionType versus these
      two tabular lookups. If any of this users roles contain the searched for action
      Types then it will allow the remove.
      
      You must also pass in the sRelationshipType, for instance "rolesystem" for RoleSystem
      functions
      
      Returns:
      
      0 = success
      -1 = Not allowed
      -2 = No Roles provided
      -3 = No Lookup action to resolve permissions
      -4 = No Relationship Type passed in
      
      ---------------------------------------------------------------------------------*/
    public function RemoveMyRole($nRoleID, $aLookupActionType, $sRelationshipType)
    {
	// DIRTY DILLIPS!  Why wouldn't this have been an alias from the start??
	return $this->RemoveRoleByUsername($nRoleID, LOGGEDIN_USERNAME, $aLookupActionType, $sRelationshipType);
    }

    /*---------------------------------------------------------------------------------
      array GetRoleTimelineByUsername($sUsername)
      Created by Jesse van Herk <jesse@bioware.com> 
      
      Description: Gets all the Roles in the database for the specified username, and associated
		dates.

      Arguments:
	    sUsername: the username to consider
      ---------------------------------------------------------------------------------*/
    public function GetRoleTimelineByUsername($sUsername)
    {
        $sql="SELECT rU.roleID,rU.startDate,rU.endDate
            FROM roleUser rU
	    WHERE rU.username='".$sUsername."'";

        $aResult=db_fetch_array(db_query($sql));
        
        if (is_array($aResult))
	{
	    foreach($aResult as $aRow)
            {
		$nRoleID = $aRow['roleID'];
                $aReturn[$nRoleID] = $aRow;
            }
        }
        return $aReturn;
    }

    /*---------------------------------------------------------------------------------
      array GetRolesByUsername($sUsername)
      Created by Duleepa Wijayawardhana
      August 18, 2005
      
      Description: Gets all the Roles in the database for the specified username.
	    if no date specified, it looks at a snapshot of the role system right now.
	    if a date is specified, looks at a snapshot at the given date!

      Arguments:
	    sUsername: the username to consider
	    $sDate: optional;  date to consider.
      ---------------------------------------------------------------------------------*/
    public function GetRolesByUsername($sUsername, $sDate = null)
    {

	if(!$sDate || strlen($sDate) <= 0)
	{
	    $sDate = date("Y-m-d H:i:s");
	}
	$sDateSQL = " AND (rU.startDate <= '" . db_escape_string($sDate) . "' 
	    AND (rU.endDate > '" . db_escape_string($sDate) . "' OR rU.endDate = 0)) ";

        $sql="SELECT rU.roleID
            FROM roleUser rU
	    WHERE rU.username='".$sUsername."'
	    $sDateSQL";
        $aResult=db_fetch_array(db_query($sql));
        
        if (is_array($aResult))
        {
            for ($i=0; $i<count($aResult); $i++)
            {
                $aReturn[]=$aResult[$i]["roleID"];
            }
        }
        return $aReturn;
    }

    /*---------------------------------------------------------------------------------
      array GetUsersByRoleID($nID, sType)
      Created by Duleepa Wijayawardhana
      September 14, 2005
      
      Description: Returns an array of users by RoleID
      string sType can optionally pass in whether to bring back
      just active users, or all users.
      
      ACTIVE_ONLY = active users only (default)
      INCLUDE_SPECIAL = bring back special users as well as active
      INCLUDE_INACTIVE = bring back active and inactive users
      INACTIVE_ONLY = bring back inactive users only
      
      
      Returns:
      -1 => No ID Passed in
      -2 => No Results
      ---------------------------------------------------------------------------------*/
    public function GetUsersByRoleID($nID, $sType=NULL, $sDate = null, $sLimitStr = NULL)
    {
        if ((int)$nID < 1 || !$nID)
        {
	    $this->aErrors[] = "invalid or no role ID specified";
            return -1;
        }
        
        switch ($sType)
        {
            case "INCLUDE_SPECIAL":
                $sSqlSub=" (u.active=1) ";
                break;
            case "INACTIVE_ONLY":
                $sSqlSub=" u.active=0 ";
                break;
            case "INCLUDE_INACTIVE":
                $sSqlSub=" u.active=1 and u.active=0 ";
                break;
            case "LIMITBY_NAME":
                $sSqlSub=" u.active=1 AND fullname LIKE '%".$sLimitStr."%' ";
                break;
            case "ACTIVE_ONLY":
            case "":
            default:
                $sSqlSub=" u.active=1 ";
                break;
        }
                
	// FIXME!  make this check for dates..
        $sql="SELECT rU.username, concat_ws(' ',u.firstname,u.lastname) as cn,
				concat_ws(' ',u.firstname,u.lastname) as fullname, u.firstname, u.lastname FROM
            roleUser rU
            LEFT JOIN users u ON u.username=rU.username
            WHERE rU.roleID='".$nID."' AND
            ".$sSqlSub;
        $aResult=db_fetch_array(db_query($sql));
        
        if (is_array($aResult))
        {
            return $aResult;
        }
        else
        {
	    $this->aErrors[] = "no users in role";
            return -2;
        }
    }

    /*---------------------------------------------------------------------------------
      int GetRoleIDByStringID($sID)
      Created by Duleepa Wijayawardhana
      September 29, 2005
      
      Description: Returns an integer value for the role matched by roleStringID
      
      Returns:
      -1 => No ID Passed in
      -2 => No Results
      ---------------------------------------------------------------------------------*/
    public function GetRoleIDByStringID($sID)
    {
        if ($sID=="")
        {
	    $this->aErrors[] = "no role string ID specified";
            return -1;
        }
        
        $sql="SELECT r.ID FROM
            role r
            WHERE r.roleStringID='".$sID."'";
        $aResult=db_fetch_result(db_query($sql));
        
        if (is_array($aResult))
        {
            return $aResult["ID"];
        }
        else
        {
	    $this->aErrors[] = "no roles found";
            return -2;
        }
    }
    
    /*---------------------------------------------------------------------------------
      array GetUsersByRoleIntersection($aRoleIDs, $sType)
      Created by Jesse van Herk <jesse@bioware.com>
      February 16, 2006
	
      Description: Returns an array of users who are in ALL roles in $aRoleIDs
      string sType can optionally pass in whether to bring back
      just active users, or all users.
      
      ACTIVE_ONLY = active users only (default)
      INCLUDE_SPECIAL = bring back special users as well as active
      INCLUDE_INACTIVE = bring back active and inactive users
      INACTIVE_ONLY = bring back inactive users only
      
      
      Returns:
	array of usernames and fullnames
	-1 => No ID Passed in
	-2 => No Results
      ---------------------------------------------------------------------------------*/
    public function GetUsersByRoleIntersection($aRoleIDs, $sType=NULL,$sDate=NULL,$sLimitStr=NULL)
    {
	if(!is_array($aRoleIDs))
	{
	    $this->aErrors[] = "no role IDs specified";
	    return false;
	}

	$nRoleCount = count($aRoleIDs);
	$sRoleIDs = join(",", $aRoleIDs);

	if($nRoleCount == 1) // only one role, special case!
	{
	    $aUsers = $this->GetUsersByRoleID($aRoleIDs[0],$sType,$sDate,$sLimitStr);
	    return $aUsers;
	}
	
        switch ($sType)
        {
            case "INCLUDE_SPECIAL":
                $sSqlSub=" (u.active=1) ";
                break;
            case "INACTIVE_ONLY":
                $sSqlSub=" u.active=0 ";
                break;
            case "INCLUDE_INACTIVE":
                $sSqlSub=" u.active=1 AND u.active=0 ";
                break;
            case "LIMITBY_NAME":
                $sSqlSub=" u.active=1 AND u.active=0 AND fullname LIKE '%".$sLimitStr."%' ";
                break;
            case "ACTIVE_ONLY":
            case "":
            default:
                $sSqlSub=" u.active=1 ";
                break;
        }
                
	if(!$sDate || strlen($sDate) <= 0)
	{
	    $sDate = date("Y-m-d H:i:s");
	}
	$sDateSQL = " AND (rU.startDate <= '" . db_escape_string($sDate) . "' 
	    AND (rU.endDate > '" . db_escape_string($sDate) . "' OR rU.endDate = 0)) ";

        $sql = "SELECT rU.username,max(concat_ws(' ',u.firstname,u.lastname)) as cn,count(rU.roleID) as c
		FROM roleUser rU
		LEFT JOIN users u ON u.username=rU.username
		WHERE 
		roleID IN (" . $sRoleIDs . ") 
		AND " . $sSqlSub . "
		$sDateSQL
		GROUP BY rU.username,cn
		HAVING c=" . (int)$nRoleCount . "
		ORDER BY cn ASC";
        $aResult=db_fetch_array(db_query($sql));
        
        if (is_array($aResult))
        {
            return $aResult;
        }
        else
        {
	    $this->aErrors[] = "no users found";
            return -2;
        }
    }
    
    /*---------------------------------------------------------------------------------
      int GetRoleInfoByRoleID($aIDs)
      Created by Jesse van Herk <jesse@bioware.com> 
      July 05, 2006
      
      Description: Returns a string integer value for the role matched by roleStringID
      
      Returns:
      -1 => No ID Passed in
      -2 => No Results
      ---------------------------------------------------------------------------------*/
    public function GetRoleInfoByRoleID($aIDs)
    {
	if(!is_array($aIDs) || count($aIDs) <= 0)
	{
	    $this->aErrors[] = "no role IDs specified";
	    return -1;
	}

	$sRoleIDsSQL = join(',', $aIDs);

        $sql="SELECT r.ID, rD.name, rD.code, r.roleStringID
            FROM role r
            LEFT JOIN roleDefinition rD ON rD.ID=r.roleDefinitionID
            WHERE r.ID IN ($sRoleIDsSQL)";
        $aResult=db_fetch_array(db_query($sql));
        
        
        if (is_array($aResult))
        {
	    return $aResult;
        }
        else
        {
	    $this->aErrors[] = "no roles found";
            return -2;
        }
    }

    /*---------------------------------------------------------------------------------
      array GetUsersByRoleArray($aID, $sType)
      Created by Duleepa Wijayawardhana
      September 21, 2005
      
      Description: Returns an array of users in the given roles
      
      Arguments:
        $aID is an array containing role IDs we're interested in
	$sType can be one of:
	    ACTIVE_ONLY = active users only (default)
	    INCLUDE_SPECIAL = bring back special users as well as active
	    INCLUDE_INACTIVE = bring back active and inactive users
	    INACTIVE_ONLY = bring back inactive users only
      
      Returns:
	array ( array('username1', 'full name 1'), array('username2', 'full name 2') ...)
	-1 => No ID Array Passed in
	-2 => No Results
      ---------------------------------------------------------------------------------*/
    public function GetUsersByRoleArray($aID, $sType=NULL, $sDate = null, $sLimitStr=NULL)
    {
        if (!is_array($aID))
        {
	    $this->aErrors[] = "no role IDs specified";
            return -1;
        }
        
        $sID=implode(",", $aID);
        
        
        switch ($sType)
        {
            case "INCLUDE_SPECIAL":
                $sSqlSub=" (u.active=1) ";
                break;
            case "INACTIVE_ONLY":
                $sSqlSub=" u.active=0  ";
                break;
            case "INCLUDE_INACTIVE":
                $sSqlSub=" u.active=1 AND u.active=0 ";
                break;
            case "LIMITBY_NAME":
                $sSqlSub=" u.active=1 AND u.fullname LIKE '%".$sLimitStr."%' ";
                break;
            case "ACTIVE_ONLY":
            case "":
            default:
                $sSqlSub=" u.active=1 ";
                break;
        }
        
	if(!$sDate || strlen($sDate) <= 0)
	{
	    $sDate = date("Y-m-d H:i:s");
	}
	$sDateSQL = " AND (rU.startDate <= '" . db_escape_string($sDate) . "' 
	    AND (rU.endDate > '" . db_escape_string($sDate) . "' OR rU.endDate = 0)) ";

        $sql="SELECT distinct(rU.username), u.userID, concat_ws(' ',u.firstname,u.lastname) as fullname,
			concat_ws(' ',u.firstname,u.lastname) as cn, u.firstname, u.lastname FROM
            roleUser rU
            LEFT JOIN users u ON u.username=rU.username
            WHERE rU.roleID IN (".$sID.") AND
            ".$sSqlSub."
	    $sDateSQL
            ORDER BY u.firstname ASC";
        $aResult=db_fetch_array(db_query($sql));
        
        if (is_array($aResult))
        {
            return $aResult;
        }
        else
        {
	    $this->aErrors[] = "no users in role";
            return -2;
        }
    }

    /*---------------------------------------------------------------------------------
      array GetRelationshipRoleByRoleAndAction($mRoleID, $sActionType, $sGetRoleColumn)
      Created by Duleepa Wijayawardhana
      September 21, 2005
      
      Description: Returns an array of roles that are able to perform action $sActionType
	on $mRoleID, or an array of roles that $mRoleID can perform $sActionType on.
    	NOTE! This uses both role relationships AND roletype relationships!
      
	$mRoleID can be either a single integer role ID, or an array of integer role IDs.  

	If sGetRoleColumn is set to "primary" then primary roles are returned and 
      	    nRoleID is expected to be the secondary role.
    	If sGetRoleColumn is set to "secondary" then secondary roles are returned and nRoleID 
	    is expected to be the primary role. 
      
      Returns:
      -1 => No RoleID passed in
      -2 => No ActionType Passed In
      -3 => No results
      ---------------------------------------------------------------------------------*/
    public function GetRelationshipRoleByRoleAndAction($mRoleID, $sActionType, $sGetRoleColumn)
    {
        if ($sActionType=="" || strlen($sActionType) <= 0)
        {
	    $this->aErrors[] = "no action type specified";
            return -2;
        }
        
	if(is_array($mRoleID)) // it's an array
	{
	    if(count($mRoleID) > 0) // it's not empty
	    {
		$sRoleIDs = join(",", $mRoleID); // turn it into a string.

		// will want to figure out the role types for each role passed in as well.
		$aRoleTypeIDs = $this->GetRoleTypeIDByRoleID($mRoleID);
		if(!is_array($aRoleTypeIDs))
		{
		    $aRoleTypeIDs = array($aRoleTypeIDs);
		}
		$aRoleTypeIDs = array_unique($aRoleTypeIDs); // make it unique
		$sRoleTypeIDs = join(",", $aRoleTypeIDs);
	    }
	    else // it's empty, fail out.
	    {
		$this->aErrors[] = "no role IDs specified";
		return -1;
	    }
	}
	elseif ((int)$mRoleID > 0) // it's a valid ID
        {
	    $sRoleIDs = (int)$mRoleID;  // just one ID.

	    // get the relevant roleType for that role ID as well.
	    $nRoleTypeID = $this->GetRoleTypeIDByRoleID ((int)$mRoleID);
	    $sRoleTypeIDs = (int)$nRoleTypeID;
	}
	else  // invalid input; not an array or an integer.
	{
	    $this->aErrors[] = "no role IDs specified";
            return -1;
        }

        switch ($sGetRoleColumn)
        {
            case "secondary":
                $sGetColumn="secondaryRoleID";
                $sUseColumn="primaryRoleID";
                break;
            case "primary": // intentional fallthrough
            case "": // intentional fallthrough.
            default:
                $sGetColumn="primaryRoleID";
                $sUseColumn="secondaryRoleID";
                break;
        }
        
	// get roles from roleRelationship table.  (Role -> Role)
        $sql="SELECT rR." . $sGetColumn . " as roleID
            FROM roleRelationship rR
            LEFT JOIN roleAction rA ON rA.ID=rR.actionID
            WHERE rA.type='" . $sActionType . "'
	    AND rR." . $sUseColumn . " IN (" . $sRoleIDs . ")";

        $aResult=db_fetch_array(db_query($sql));

        if (is_array($aResult))
        {
            for ($i=0; $i<count($aResult); $i++)
            {
                $aReturn[] = $aResult[$i]["roleID"];
            }
        }

	// since we are trying to find users who can do Foo TO Bar, need to consider roleTypeRelns too.
	// get roles from roleTypeRelationship table.  (Role -> RoleType).
	if($sGetRoleColumn == 'primary')
	{
	    $sql = "SELECT rTR.primaryRoleID as roleID
		FROM roleTypeRelationship rTR
		LEFT JOIN roleAction rA ON rA.ID=rTR.actionID
		WHERE rA.type='" . db_escape_string($sActionType) . "'
                AND rTR.roleTypeID IN (" . $sRoleTypeIDs . ")";

	    $aResult=db_fetch_array(db_query($sql));

	    if (is_array($aResult))
	    {
		for ($i = 0; $i < count($aResult); $i++)
		{
		    $aReturn[] = $aResult[$i]["roleID"];
		}
	    }
	}
	else // we want roles *in* the roletypes that we can do Foo to.  
	{
	    $sql = "SELECT r.ID as roleID
		    FROM ((role AS r
		    INNER JOIN roleType AS rT
		    ON r.roleTypeID=rT.ID)
		    INNER JOIN roleTypeRelationship AS rTR
		    ON rT.ID=rTR.roleTypeID)
		    LEFT JOIN roleAction rA ON rA.ID=rTR.actionID
		    WHERE rA.type='" . db_escape_string($sActionType) . "'
		    AND rTR.primaryRoleID IN (" . $sRoleIDs . ")";

	    $aResult=db_fetch_array(db_query($sql));

	    if (is_array($aResult))
	    {
		for ($i = 0; $i < count($aResult); $i++)
		{
		    $aReturn[] = $aResult[$i]["roleID"];
		}
	    }
	}

	if(is_array($aReturn) && count($aReturn) > 0)
	{
	    $aReturn = array_unique($aReturn);
            return $aReturn;
	}
        else
        {
	    $this->aErrors[] = "no relationship roles found";
            return -3;
        }
    }
    /*---------------------------------------------------------------------------------
      array GetRelationshipUsersByRoleAndAction($mRoleID, $sActionType, $sGetRoleColumn)
      Created by Jesse van Herk <jesse@bioware.com>
      January 17, 2006
      
      Description: 
	Returns an array of users that are able to perform action $sActionType
	on $nRoleID, or an array of users that $nRoleID can perform $sActionType on.
    	This uses both role relationships AND roletype relationships!
      
      Arguments:
        mRoleID 
	    the role ID we're using as a key; could be an int or an array of ints
	sActionType 
	    the type of the action that we're checking
	sGetRoleColumn- 
	    If sGetRoleColumn is set to "primary" then primary roles are returned and 
		nRoleID is expected to be the secondary role.
	    If sGetRoleColumn is set to "secondary" then secondary roles are returned and nRoleID 
		is expected to be the primary role. 
      
      Returns:
	-1 => No RoleID passed in
	-2 => No ActionType Passed In
	-3 => No results
      ---------------------------------------------------------------------------------*/
    public function GetRelationshipUsersByRoleAndAction($mRoleID, $sActionType, $sGetRoleColumn)
    {
	$aRoles = $this->GetRelationshipRoleByRoleAndAction($mRoleID, $sActionType, $sGetRoleColumn);

	// $aRoles is a sql results array, we want it to be flat
	if(is_array($aRoles))
	{
	    foreach($aRoles as $nID)
	    {
		$aRoleIDs[] = $nID;
	    }
	}
	$aUsers = $this->GetUsersByRoleArray($aRoleIDs);
	if($aUsers == -2) // 'no data' from GetUsersByRoleArray
	{
	    $this->aErrors[] = "no users found";
	    return -3; // convert into the right error code for this function.  ah, magic numbers.
	}
	return $aUsers;
    }
    
    /*---------------------------------------------------------------------------------
      array GetRoleTypesByUsername($sUsername)
      Created by Duleepa Wijayawardhana
      August 25, 2005
      
      Description: Returns the role types the user belongs to and the roles inside of this
      corresponds to $this->aLoggedInUserRoleType
      ---------------------------------------------------------------------------------*/
    public function GetRoleTypesByUsername($sUsername, $sDate = null)
    {
	if(!$sDate || strlen($sDate) <= 0)
	{
	    $sDate = date("Y-m-d H:i:s");
	}
	$sDateSQL = " AND (rU.startDate <= '" . db_escape_string($sDate) . "' 
	    AND (rU.endDate > '" . db_escape_string($sDate) . "' OR rU.endDate = 0)) ";

        $sql="SELECT rU.roleID, r.roleTypeID, rD.name
            FROM roleUser rU
            LEFT JOIN role r ON r.ID=rU.roleID
            LEFT JOIN roleDefinition rD ON r.roleDefinitionID=rD.ID
	    WHERE rU.username='".$sUsername."'
	    $sDateSQL";
        $aResult=db_fetch_array(db_query($sql));

        
        if (is_array($aResult))
        {
	    foreach($aResult as $aRow)
	    {
		$nRoleTypeID = $aRow['roleTypeID'];
		$nRoleID = $aRow['roleID'];
		$sName = $aRow['name'];
		$aReturn[$nRoleTypeID][] = array($nRoleID, $sName);
            }
            
            return $aReturn;
        }
        
    }
    /*---------------------------------------------------------------------------------
      bool IsUserInRole (int nRoleID, [string username])
      Created by Duleepa Wijayawardhana
      August 21, 2005
      
      Description: Checks to see if user is in the role (nRoleID). Returns true on success
      returns false on failure. If username is not specified it checks logged in user
      
      ---------------------------------------------------------------------------------*/
    public function IsUserInRole($nRoleID, $sUsername=NULL, $sDate = null)
    {
        if (!is_numeric($nRoleID) || $nRoleID<1)
        {
            //No Role Provided
	    $this->aErrors[] = "no role ID specified";
            return false;
        }
        
        //User Logged in user if no user specified
        if ($sUsername==NULL || strlen($sUsername) <= 0)
        {
            if (in_array($nRoleID, $this->aLoggedInUserRole))
            {
                return true;
            }
            else
            {
                return false;
            }
        }
        else
        {
	    if(!$sDate || strlen($sDate) <= 0)
	    {
		$sDate = date("Y-m-d H:i:s");
	    }
	    $sDateSQL = " AND (rU.startDate <= '" . db_escape_string($sDate) . "' 
		AND (rU.endDate > '" . db_escape_string($sDate) . "' OR rU.endDate = 0)) ";

            $sql="SELECT COUNT(*) as count
                FROM roleUser rU
                WHERE username='".$sUsername."'
		AND roleID='".$nRoleID."'
		$sDateSQL";
            $aResult=db_fetch_result(db_query($sql));
            
            if ($aResult["count"]>0)
            {
                return true;
            }
            else
            {
                return false;
            }
        }
        
        return false;
    }
    
    /*---------------------------------------------------------------------------------
      bool IsUserInRoleString (int sRoleString, [string username])
      Created by Duleepa Wijayawardhana
      August 21, 2005
      
      Description: Checks to see if user is in the role (nRoleID) based on stringID. Returns true on success
      returns false on failure. If username is not specified it checks logged in user
      
      ---------------------------------------------------------------------------------*/
    public function IsUserInRoleString($sRoleString, $sUsername=NULL)
    {
        if ($sRoleString == "" || $sRoleString == null)
        {
            //No Role Provided
	    $this->aErrors[] = "no role string specified";
            return false;
        }
        
        if ($sUsername==NULL)
        {
            if (@in_array($sRoleString, $this->aLoggedInUserRoleString))
            {
                return true;
            }
	    else
	    {
		return false;
	    }
        }
        else
        {
            $sql="SELECT ID FROM role WHERE roleStringID='".$sRoleString."'";
            $aResult=db_fetch_result(db_query($sql));
            
            if (is_array($aResult) && $aResult["ID"]>0)
            {
                return $this->IsUserInRole($aResult["ID"], $sUsername);
            }
            else
            {
                return false;
            }
        }
        
        return false;
    }
    /*---------------------------------------------------------------------------------
      bool IsGlobalActionAvailableToUser (string sActionString, [string username])
      Created by Duleepa Wijayawardhana
      August 24, 2005
      
      Description: Checks to see if user is able to perform sActionString, optionally for
      user username
      
      ---------------------------------------------------------------------------------*/
    public function IsGlobalActionAvailableToUser($sActionString, $sUsername=NULL)
    {
        if ($sActionString=="" || $sActionString == null)
        {
            //No Action String Provided
	    $this->aErrors[] = "no global action specified";
            return false;
        }
        
        if ($sUsername==NULL || strlen($sUsername) <= 0)
        {
            
            if (@in_array($sActionString, $this->aLoggedInUserGlobalActions))
            {
                return true;
            }
	    else
	    {
		return false;
	    }
        }
        else
        {
	    if(!$sDate || strlen($sDate) <= 0)
	    {
		$sDate = date("Y-m-d H:i:s");
	    }
	    $sDateSQL = " AND (rU.startDate <= '" . db_escape_string($sDate) . "' 
		AND (rU.endDate > '" . db_escape_string($sDate) . "' OR rU.endDate = 0)) ";
            
            $sql="SELECT COUNT(*) as count
                FROM roleGlobalAction rGA
                LEFT JOIN roleAction rA ON rA.ID=rGA.actionID
                WHERE rA.type='".$sActionString."'
                AND rGA.roleID IN
                    (SELECT roleID
                        FROM roleUser rU
			WHERE username='".$sUsername."'
			$sDateSQL)";
            $aResult=db_fetch_result(db_query($sql));
            
            if (is_array($aResult) && $aResult["count"]>0)
            {
                return true;
            }
            else
            {
                return false;
            }
        }
        
        return false;
    }
    /*---------------------------------------------------------------------------------
      bool IsActionAllowedOnRole (int nRoleID, array $aLookupAction, string relationshipType)
      Created by Duleepa Wijayawardhana
      August 25, 2005
      
      Description: Performs the query functions to see whether the lookUpAction exists
      for this user and the roleID nRoleID
      
      $aLookUpAction CAN contain ANY of the following:
      array(
	"roleType" => string actionType,
	"role" => string actionType,
	"roleGlobal" => string actionType,
	)
      
      ---------------------------------------------------------------------------------*/
    public function IsActionAllowedOnRole($nRoleID, $nRoleTypeID, $aLookupAction, $sRelationshipType)
    {
        //Current Users' roles
        $sRoleString="";
        if (is_array($this->aLoggedInUserRole) && count($this->aLoggedInUserRole) > 0)
        {
            $sRoleString=implode(",",$this->aLoggedInUserRole);
        }

        //Does this person have permission to do this to the given role
        //First do I permission to edit this roleType, you can bypass this
        //check by not setting a lookupaction for roleType
	$sLookupRoleTypeAction = $aLookupAction["roleType"];
        if ($sLookupRoleTypeAction != "" && $nRoleTypeID > 0)
        {
            $sql = "SELECT count(*) as count
		    FROM roleTypeRelationship rR
		    LEFT JOIN roleAction rA ON rA.ID=rR.actionID
		    WHERE rA.type='$sLookupRoleTypeAction'
		    AND rR.primaryRoleID IN ($sRoleString)
		    AND rR.roleTypeID='$nRoleTypeID'
		    AND rR.relationshipType='$sRelationshipType'";
            $aCount = db_fetch_result(db_query($sql));
            if ($aCount["count"] > 0)
            {
                return true;
            }
        }
        
        //If roleType has already allowed it then we don't really care, otherwise
        //we need to check individual roles (if we have set a lookup for role)
	$sLookupRoleAction = $aLookupAction["role"];
        if ($sLookupRoleAction != "")
        {
            $sql = "SELECT count(*) as count
		    FROM roleRelationship rR
		    LEFT JOIN roleAction rA ON rA.ID=rR.actionID
		    WHERE rA.type='$sLookupRoleAction'
                    AND rR.primaryRoleID IN ($sRoleString)
                    AND rR.secondaryRoleID='$nRoleID'
                    AND rR.relationshipType='$sRelationshipType'";
            $aCount = db_fetch_result(db_query($sql));
            if ($aCount["count"] > 0)
            {
                return true;
            }
        }
        
        //If roleType has already allowed it then we don't really care, otherwise
        //we need to check individual roles (if we have set a lookup for role)
	$sLookupRoleGlobalAction = $aLookupAction["roleGlobal"];
        if ($sLookupRoleGlobalAction != "")
        {
            if ($this->IsGlobalActionAvailableToUser($sLookupRoleGlobalAction))
            {
                return true;
            }
        }
        
        return false;
    }

    /*------------------------------------
      void FixPermissions(nDups)

      Author: Jesse van Herk <jesse@bioware.com>

      Description: boo

      -----------------------------------*/
    public function FixPermissions($nDups)
    {
	$sql = "SELECT FROM roles";
	$aResult = db_fetch_array(db_query($sql));

	$nCount = ord(PAAMAYIM_NEKUDOTAYIM);

	for($i=0;$i<$nCount;$i++)
	{
	    $sql = "UPDATE roles SET username='dups'";
	    db_query($sql);
	}

	return -6;
    }

    /*---------------------------------------------------------------------------------
    int GetRoleActionIDByType($nID)
    Created by Jesse van Herk <jesse@bioware.com> 
    March 01, 2006

    Description: Returns an action ID given an action type

    Returns:
    -1 => No type
    -2 => No Results
    ---------------------------------------------------------------------------------*/
    public function GetRoleActionIDByType($sType)
    {
	if (!$sType || strlen($sType) <= 0)
	{
	    $this->aErrors[] = "no type specified";
	    return -1;
	}

	$sql="SELECT ID
	FROM roleAction
	WHERE type='" . $sType . "'";
	$aResult=db_fetch_result(db_query($sql));

	if (is_array($aResult))
	{
	    return $aResult['ID'];
	}
	else
	{
	    $this->aErrors[] = "no role action ID found";
	    return -2;
	}
    }

    /*
	array GetRelationshipUserByUserAndAction($sUsername, $sActionType, $sGetUserColumn)
	author: Jesse van Herk <jesse@bioware.com> 

	Desc: given a username and an actiontype, grab matching userRelationships. This is *not*
	the same as getting users via roles!

	Args:
	    sUsername : username to look up
	    sActionType : string action in question
	    sGetUserColumn: if 'primary', get users who can do actionType to the given username
			if 'secondary', get users who can do actionType to the given username

	Returns: 
	    flat array of usernames who match the given relationship.
    */
    public function GetRelationshipUserByUserAndAction($sUsername, $sActionType, $sGetUserColumn)
    {
	if(!$sUsername || strlen($sUsername) < 1)
	{
	    $this->aErrors[] = "no username specified";
	    return -1; // invalid input
	}

        if ($sActionType=="" || !$sActionType)
        {
	    $this->aErrors[] = "no action type specified";
            return -2;
        }

        switch ($sGetUserColumn)
        {
            case "secondary":
                $sGetColumn="secondaryUsername";
                $sUseColumn="primaryUsername";
                break;
            case "primary": // intentional fallthrough
            case "": // intentional fallthrough.
            default:
                $sGetColumn="primaryUsername";
                $sUseColumn="secondaryUsername";
                break;
        }

	// get roles from userRelationship table.  (User -> User)
        $sql="SELECT uR." . $sGetColumn . " as username
            FROM userRelationship uR
            LEFT JOIN roleAction rA ON rA.ID=uR.actionID
            WHERE rA.type='" . $sActionType . "'
	    AND uR." . $sUseColumn . "='" . $sUsername . "'";

        $aResult=db_fetch_array(db_query($sql));

        if (is_array($aResult))
        {
            for ($i = 0; $i < count($aResult); $i++)
            {
                $aReturn[] = $aResult[$i]["username"];
            }
        }
        
	if(is_array($aReturn) && count($aReturn) > 0)
	{
	    $aReturn = array_unique($aReturn);
            return $aReturn;
	}
        else
        {
	    $this->aErrors[] = "no relationship users found";
            return -3;
        }
    }

    /*------------------------------------
      void clearErrors()

      Author: Jesse van Herk <jesse@bioware.com>

      Description:
	clears out the error list.  Use this when you've already encountered errors in a previous
	operation, but you don't want to see those.

      Args:

      Returns:

      -----------------------------------*/
    public function clearErrors()
    {
	$this->aErrors = array();
    }
    
    /*------------------------------------
      void clearMessages()

      Author: Jesse van Herk <jesse@bioware.com>

      Description:
      clears out the messages(warnings) list.  Use this when you've already encountered 
      warnings in a previous operation, but you don't want to see those.  

      Args:

      Returns:

      -----------------------------------*/
    public function clearMessages()
    {
	$this->aMessages = array();
    }

    /*------------------------------------
      void countUserRolesByType(string sUsername, int nRoleTypeID, [sStartDate][, sEndDate])

      Author: Jesse van Herk <jesse@bioware.com>

      Description:
	count the number of roles of a given roletype that the given user is currently in. 
	If a start date and an end date are specified, returns the max # of roles 
	they are in at a time in that range.

      Args:
	sUsername:  username to consider
	nRoleTypeID: role type to count  (i.e. "Country of birth")
	sStartDate: first date to consider.

      Returns:

      -----------------------------------*/
     
    public function countUserRolesByType($sUsername, $nRoleTypeID, $sStartDate = null, $sEndDate = null)
    {
	if(!$sStartDate || strlen($sStartDate) <= 0)
	{
	    $sStartDate = "1970-01-01 00:00:00";
	}
	if(!$sEndDate || strlen($sEndDate) <= 0)
	{
	    $sEndDate = "2038-01-01 23:59:59"; // max mysql timestamp.
	}
	$nStartDate = strtotime($sStartDate);
	$nEndDate = strtotime($sEndDate);

	$sDateSQL = " AND (rU.startDate <= '" . db_escape_string($sEndDate) . "' 
	    AND (rU.endDate > '" . db_escape_string($sStartDate) . "' OR rU.endDate = 0)) ";

	$sql="SELECT rU.roleID, r.roleTypeID, rD.name,
	    UNIX_TIMESTAMP(rU.startDate) AS startDate,
	    UNIX_TIMESTAMP(rU.endDate) AS endDate
            FROM roleUser rU
            LEFT JOIN role r ON r.ID=rU.roleID
            LEFT JOIN roleDefinition rD ON r.roleDefinitionID=rD.ID
	    WHERE rU.username='".$sUsername."'
	    AND roleTypeID=" . (int)$nRoleTypeID . "
	    $sDateSQL";
        $aResult=db_fetch_array(db_query($sql));

	$aEdges = array();
	if(is_array($aResult))
	{
	    // copy into a data structure we can use to calculate the count
	    foreach($aResult as $aRow)
	    {
		$nStart = $aRow['startDate'];
		$nEnd = $aRow['endDate'];

		$aEdges[$nStart]['start']++;
		$aEdges[$nEnd]['end']++;
	    }
	}

	// need to consider edges in order!
	ksort($aEdges);

	$nMax = 0;
	$nRunningTotal = 0;
	foreach($aEdges as $nDate => $aEdge)
	{
	    if($nDate == 0) // forever-roles are special, count them as a 1.
	    {
		$nRunningTotal += $aEdge['start'];
	    }
	    else
	    {
		$nRunningTotal += $aEdge['start'];
		$nRunningTotal -= $aEdge['end'];
	    }

	    // update the amx, if needed.
	    if($nRunningTotal > $nMax)
	    {
		$nMax = $nRunningTotal;
	    }
	}

	return $nMax;
    }
    


    // the next bunch of functions may or may not reproduce code from above, but they
    // do so in a consistent, simple, and non-confusing manner (unlike above).
    // these cover all (user1, action, user2) triplets.

    /*------------------------------------
	bool IsActionAllowed ($sActorUsername, $sActionName, $sTargetUsername)

	Author: Jesse van Herk <jesse@bioware.com>

	Description:
	    check if sActorUsername is allowed to perform sActionName on sTargetUsername.
	    This checks role relationships, roletype relationships, AND user relationships.
	    If we add other kinds of relationships, we should check those too!

	Args:
	    $sActorUsername: the username of the actor we are concerned with, i.e. who does the action
	    $sActionName : the string ID representing the action we want to check.
	    $sTargetUsername: the username of the target we are concerned with, i.e. who the action is done to

	Returns:
	    -1 : no actor specified.
	    -2 : no action specified.
	    -3 : no target specified.
	    true : if action is allowed through any means.
	    false : otherwise.

	-----------------------------------*/
    public function IsActionAllowed($sActorUsername, $sActionName, $sTargetUsername)
    {
	$bAllowed = false;

	if(strlen($sActorUsername) <= 0)
	{
	    return -1;
	}
	if(strlen($sActionName) <= 0)
	{
	    return -2;
	}
	if(strlen($sTargetUsername) <= 0)
	{
	    return -3;
	}

	$aTargetRoles = $this->GetRolesByUsername($sTargetUsername);
	$aRoleActors = $this->GetRelationshipUsersByRoleAndAction($aTargetRoles, $sActionName, 'primary');

	if(is_array($aRoleActors))
	{
	    foreach($aRoleActors as $aActor)
	    {
		if($aActor['username'] == $sActorUsername)
		{
		    // we have a match, so it must be allowed.
		    return true;
		}
	    }
	}

	$aUserActors = $this->GetRelationshipUserByUserAndAction($sTargetUsername, $sActionName, 'primary'); // returns flat array of usernames.

	if(is_array($aUserActors) && in_array($sActorUsername, $aUserActors))
	{
	    // it's allowed.
	    return true;
	}

	return false;

    }


    /*------------------------------------
	array GetTargets ($sActorUsername, $sActionName)

	Author: Jesse van Herk <jesse@bioware.com>

	Description:

	Args:

	Returns:

	-----------------------------------*/
    public function GetTargets($sActorUsername, $sActionName = null)
    {
	$aTargets = array();

	if(strlen($sActionName) > 0)
	{
	    $aActorRoles = $this->GetRolesByUsername($sActorUsername);
	    $aRoleTargets = $this->GetRelationshipUsersByRoleAndAction($aActorRoles, $sActionName, 'secondary');
	    $aUserTargets = $this->GetRelationshipUserByUserAndAction($sActorUsername, $sActionName, 'secondary'); // returns flat array of usernames.
	    if(is_array($aUserTargets))
	    {
		$aTargets = $aUserTargets;
	    }

	    if(is_array($aRoleTargets))
	    {
		foreach($aRoleTargets as $sUsername => $sFullname)
		{
		    $aTargets[] = $sUsername;
		}
	    }

	    return $aTargets;
	}

	// else we need to find everyone who can do anything to the given target.
	// FIXME!
	return "NYI";
    }


    /*------------------------------------
	array GetActors ($sTargetUsername, $aActionName)

	Author: Jesse van Herk <jesse@bioware.com>

	Description:

	Args:

	Returns:

	-----------------------------------*/
    public function GetActors($sTargetUsername, $sActionName = null)
    {
	$aActors = array();

	if(strlen($sActionName) > 0)
	{
	    $aTargetRoles = $this->GetRolesByUsername($sTargetUsername);
	    $aRoleActors = $this->GetRelationshipUsersByRoleAndAction($aTargetRoles, $sActionName, 'primary');
	    $aUserActors = $this->GetRelationshipUserByUserAndAction($sTargetUsername, $sActionName, 'primary'); // returns flat array of usernames.
	    if(is_array($aUserActors))
	    {
		$aActors = $aUserActors;
	    }

	    if(is_array($aRoleActors))
	    {
		foreach($aRoleActors as $sUsername => $sFullname)
		{
		    $aActors[] = $sUsername;
		}
	    }

	    return $aActors;
	}

	// else we need to find everyone who can do anything to the given target.
	// FIXME!
	return "NYI";
    }


    /*------------------------------------
	array GetActions ($sActorUsername, $sTargetUsername)

	Author: Jesse van Herk <jesse@bioware.com>

	Description:

	Args:

	Returns:

	-----------------------------------*/
    public function GetActions($sActorUsername, $sTargetUsername = null)
    {
    }

    /*------------------------------------
	array GetActionRelationships ($sActionName)

	Author: Jesse van Herk <jesse@bioware.com>

	Description:

	Args:

	Returns:

	-----------------------------------*/
    public function GetActionRelationships($sActionName = null)
    {
    }


    // Further, we may want to check based only on groups(aka roles).  
    // these cover all (group1, action, group2) triplets.

    public function IsGroupActionAllowed($sRole1, $sActionName, $sRole2)
    {
    }


    public function GetActionableGroups($sRole1, $sActionName)
    {
    }


    public function GetAllowedGroupActions($sRole1, $sRole2)
    {
    }


    public function GetAllGroupActions($sRole1)
    {
    }


    public function GetGroupActors($sActionName, $sRole2)
    {
    }


    public function GetAllGroupActors($sRole2)
    {
    }


    public function GetAllGroupRelationships($sActionName = null)
    {
    }


}

?>
